package util

import (
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unicode"
)

var gIDWithNumberPattern1 *regexp.Regexp
var gIDWithNumberPattern2 *regexp.Regexp
var gIDWithNumberPattern3 *regexp.Regexp

func init() {
	gIDWithNumberPattern1 = regexp.MustCompile(`\S*(id)[0-9]+$`)
	gIDWithNumberPattern2 = regexp.MustCompile(`\S*(Id)[0-9]+$`)
	gIDWithNumberPattern3 = regexp.MustCompile(`\S*(iD)[0-9]+$`)
}

// 格式化字段名, 比如: xlsx表字段, mysql表字段
func FormatFieldName(rawName string) string {
	name := rawName
	words := strings.Split(rawName, "_")
	for _, word := range words {
		word = strings.TrimSpace(word)
		if word == "" {
			continue
		}
		word = strings.Title(word)
		name += word
	}

	if strings.ToLower(name) == "id" {
		name = "ID"
	}

	if strings.HasSuffix(name, "id") {
		name = strings.Replace(name, "id", "ID", 1)
	} else if strings.HasSuffix(name, "Id") {
		name = strings.Replace(name, "Id", "ID", 1)
	} else if strings.HasSuffix(name, "iD") {
		name = strings.Replace(name, "iD", "ID", 1)
	} else if gIDWithNumberPattern1.MatchString(name) {
		name = strings.Replace(name, "id", "ID", 1)
	} else if gIDWithNumberPattern2.MatchString(name) {
		name = strings.Replace(name, "Id", "ID", 1)
	} else if gIDWithNumberPattern3.MatchString(name) {
		name = strings.Replace(name, "iD", "ID", 1)
	}

	return name
}

func UpperFirst(str string) string {
	for i, v := range str {
		return string(unicode.ToUpper(v)) + str[i+1:]
	}
	return ""
}

func LowerFirst(str string) string {
	for i, v := range str {
		return string(unicode.ToLower(v)) + str[i+1:]
	}
	return ""
}

func DeserializeFromStringArray(i any, stringArray []string) (err error) {
	v := reflect.ValueOf(i).Elem()
	t := reflect.TypeOf(i)
	for i := 0; i < v.NumField(); i++ {
		column := i + 1

		tf := t.Field(i)
		tagColumnValue := tf.Tag.Get("column")
		if tagColumnValue != "" {
			if column, err = strconv.Atoi(tagColumnValue); err != nil {
				return fmt.Errorf("parse [%v][%v] fail, %v",
					i+1, t.Field(i).Name, err)
			}
		}

		f := v.Field(i)
		switch f.Type().Name() {
		case "int32", "int", "int64":
			temp, err := strconv.ParseInt(stringArray[column], 10, 0)
			if err != nil {
				return fmt.Errorf("parse [%v][%v] fail, row[%v]=[%v]",
					column, t.Field(i).Name, column+1, stringArray[column])
			}
			f.SetInt(temp)

		case "string":
			f.SetString(stringArray[i+1])

		case "bool":
			temp, err := strconv.ParseInt(stringArray[i+1], 10, 0)
			if err != nil {
				return fmt.Errorf("parse [%v][%v] fail, row[%v]=[%v]",
					column, t.Field(i).Name, column+1, stringArray[column])
			}
			f.SetBool(temp != 0)

		case "Duration":
			temp, err := strconv.ParseInt(stringArray[i+1], 10, 0)
			if err != nil {
				return fmt.Errorf("parse [%v][%v] fail, row[%v]=[%v]",
					column, t.Field(i).Name, column+1, stringArray[column])
			}
			f.SetInt(temp * int64(time.Millisecond))

		default:
			return fmt.Errorf("parse [%v][%v] fail, unsupported field type",
				column, t.Field(i).Name)
		}
	}
	return nil
}

func Format(format string, args ...any) string {
	if len(args) == 0 {
		return format
	}

	if format != "" {
		return fmt.Sprintf(format, args...)
	}

	if len(args) == 1 {
		if str, ok := args[0].(string); ok {
			return str
		}
	}

	return fmt.Sprint(args...)
}
